package com.clp.protocol.iec104.apdu.asdu.infoobj.qua;

import com.clp.protocol.iec104.definition.Tp;
import com.clp.protocol.iec104.definition.TypeTag;
import com.clp.protocol.core.pdu.nbytepdu.BaseNBytePduClip;
import com.clp.protocol.core.pdu.ByteToStringFormat;
import io.netty.buffer.ByteBuf;
import lombok.Getter;

import java.util.Objects;
import java.util.function.Consumer;

/**
 * 遥脉限定词 - 品质描述词
 */
@Getter
public abstract class TpQua extends Qua {
    private Tp.Iv iv;
    private Tp.Ca ca;
    private Tp.Cy cy;
    private int seq;

    protected TpQua(boolean isValid, boolean isAdjusted, boolean isOverflowed, int seq) {
        super(TypeTag.M_IT_NA_1);
        this.iv = Tp.Iv.gain(isValid);
        this.ca = Tp.Ca.gain(isAdjusted);
        this.cy = Tp.Cy.gain(isOverflowed);
        this.seq = seq;
    }

    protected TpQua(TypeTag typeTag, Tp.Iv iv, Tp.Ca ca, Tp.Cy cy, int seq) {
        super(typeTag);
        this.iv = iv;
        this.ca = ca;
        this.cy = cy;
        this.seq = seq;
    }

    public boolean isTpValid() {
        return iv == Tp.Iv.VALID;
    }

    public boolean isTpAdjusted() {
        return ca == Tp.Ca.CA_YES;
    }

    public boolean isTpOverflowed() {
        return cy == Tp.Cy.CY_YES;
    }

    @Override
    public TpQua refreshFrom(ByteBuf buf) {
        byte by = buf.readByte();
        this.iv = Tp.Iv.gain((by & 0x80) == 0x80 ? 1 : 0);
        this.ca = Tp.Ca.gain((by & 0x40) == 0x40 ? 1 : 0);
        this.cy = Tp.Cy.gain((by & 0x20) == 0x20 ? 1 : 0);
        this.seq = by & 0x1F;
        return this;
    }

    @Override
    public boolean isValid() {
        if (iv == null || ca == null || cy == null) return false;
        if (seq < 0 || seq > 0x1F) return false;
        return true;
    }

    @Override
    public void writeBytesTo(ByteBuf buf) {
        buf.writeByte(genByte());
    }

    private byte genByte() {
        byte by = 0x00;
        if (iv.getVal() == 1) by |= 0x80;
        if (ca.getVal() == 1) by |= 0x40;
        if (cy.getVal() == 1) by |= 0x20;
        by |= (seq & 0x1F);
        return by;
    }

    @Override
    public void writeFormattedByteStringsTo(StringBuilder sb, String frameClipBytesSeparator, String byteSeparator, ByteToStringFormat byteFormat) {
        sb.append(byteFormat.format(genByte()));
    }

    @Override
    protected void forEachOneLevelChild(Consumer<BaseNBytePduClip<?>> consumer) {
    }

    @Override
    public void writeDetailDescriptionTo(StringBuilder sb) {
        sb.append("有效位Iv：").append(iv.getDesc()).append("(").append(iv.getVal()).append(")")
                .append(", 调整位Ca：").append(ca.getDesc()).append("(").append(ca.getVal()).append(")")
                .append(", 溢出位Cy：").append(cy.getDesc()).append("(").append(cy.getVal()).append(")")
                .append(", 序号Seq：").append(seq);
    }

    @Override
    public void writeSimpleDescriptionTo(StringBuilder sb) {
        sb.append("Iv：").append(iv.getVal()).append(", Ca：").append(ca.getVal()).append(", Cy：").append(cy.getVal())
        .append(", Seq：").append(seq);
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        TpQua tpQua = (TpQua) o;
        return seq == tpQua.seq && iv == tpQua.iv && ca == tpQua.ca && cy == tpQua.cy;
    }

    @Override
    public int hashCode() {
        return Objects.hash(iv, ca, cy, seq);
    }
}
